home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / rcp / RCS / rcp.c,v < prev   
Encoding:
Text File  |  1993-01-03  |  21.0 KB  |  1,010 lines

  1. head     1.1;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    shirriff:1.1; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.1
  10. date     93.01.03.00.18.44;  author shirriff;  state Exp;
  11. branches ;
  12. next     ;
  13.  
  14.  
  15. desc
  16. @@
  17.  
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*
  26.  * Copyright (c) 1983, 1990 The Regents of the University of California.
  27.  * All rights reserved.
  28.  *
  29.  * Redistribution and use in source and binary forms, with or without
  30.  * modification, are permitted provided that the following conditions
  31.  * are met:
  32.  * 1. Redistributions of source code must retain the above copyright
  33.  *    notice, this list of conditions and the following disclaimer.
  34.  * 2. Redistributions in binary form must reproduce the above copyright
  35.  *    notice, this list of conditions and the following disclaimer in the
  36.  *    documentation and/or other materials provided with the distribution.
  37.  * 3. All advertising materials mentioning features or use of this software
  38.  *    must display the following acknowledgement:
  39.  *    This product includes software developed by the University of
  40.  *    California, Berkeley and its contributors.
  41.  * 4. Neither the name of the University nor the names of its contributors
  42.  *    may be used to endorse or promote products derived from this software
  43.  *    without specific prior written permission.
  44.  *
  45.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  46.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  47.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  48.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  49.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  50.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  51.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  52.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  53.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  54.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  55.  * SUCH DAMAGE.
  56.  */
  57.  
  58. #ifndef lint
  59. char copyright[] =
  60. "@@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
  61.  All rights reserved.\n";
  62. #endif /* not lint */
  63.  
  64. #ifndef lint
  65. static char sccsid[] = "@@(#)rcp.c    5.32 (Berkeley) 2/25/91";
  66. #endif /* not lint */
  67.  
  68. /*
  69.  * rcp
  70.  */
  71. #include <sys/param.h>
  72. #include <sys/stat.h>
  73. #include <sys/time.h>
  74. #include <sys/ioctl.h>
  75. #include <sys/socket.h>
  76. #include <sys/wait.h>
  77. #include <netinet/in.h>
  78. #include <netinet/in_systm.h>
  79. #include <netinet/ip.h>
  80. #include <dirent.h>
  81. #include <fcntl.h>
  82. #include <signal.h>
  83. #include <pwd.h>
  84. #include <netdb.h>
  85. #include <errno.h>
  86. #include <unistd.h>
  87. #include <stdio.h>
  88. #include <stdlib.h>
  89. #include <string.h>
  90. #include <ctype.h>
  91. #include "pathnames.h"
  92.  
  93. #ifdef KERBEROS
  94. #include <kerberosIV/des.h>
  95. #include <kerberosIV/krb.h>
  96. char    dst_realm_buf[REALM_SZ];
  97. char    *dest_realm = NULL;
  98. int    use_kerberos = 1;
  99. CREDENTIALS     cred;
  100. Key_schedule    schedule;
  101. extern    char    *krb_realmofhost();
  102. #ifdef CRYPT
  103. int    doencrypt = 0;
  104. #define    OPTIONS    "dfk:prtx"
  105. #else
  106. #define    OPTIONS    "dfk:prt"
  107. #endif
  108. #else
  109. #define    OPTIONS "dfprt"
  110. #endif
  111.  
  112. struct passwd *pwd;
  113. u_short    port;
  114. uid_t    userid;
  115. int errs, rem;
  116. int pflag, iamremote, iamrecursive, targetshouldbedirectory;
  117.  
  118. #define    CMDNEEDS    64
  119. char cmd[CMDNEEDS];        /* must hold "rcp -r -p -d\0" */
  120.  
  121. typedef struct _buf {
  122.     int    cnt;
  123.     char    *buf;
  124. } BUF;
  125.  
  126. void lostconn();
  127.  
  128. main(argc, argv)
  129.     int argc;
  130.     char **argv;
  131. {
  132.     extern int optind;
  133.     extern char *optarg;
  134.     struct servent *sp;
  135.     int ch, fflag, tflag;
  136.     char *targ, *shell, *colon();
  137.  
  138.     fflag = tflag = 0;
  139.     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
  140.         switch(ch) {
  141.         /* user-visible flags */
  142.         case 'p':            /* preserve access/mod times */
  143.             ++pflag;
  144.             break;
  145.         case 'r':
  146.             ++iamrecursive;
  147.             break;
  148. #ifdef    KERBEROS
  149.         case 'k':
  150.             strncpy(dst_realm_buf, optarg, REALM_SZ);
  151.             dest_realm = dst_realm_buf;
  152.             break;
  153. #ifdef CRYPT
  154.         case 'x':
  155.             doencrypt = 1;
  156.             /* des_set_key(cred.session, schedule); */
  157.             break;
  158. #endif
  159. #endif
  160.         /* rshd-invoked options (server) */
  161.         case 'd':
  162.             targetshouldbedirectory = 1;
  163.             break;
  164.         case 'f':            /* "from" */
  165.             iamremote = 1;
  166.             fflag = 1;
  167.             break;
  168.         case 't':            /* "to" */
  169.             iamremote = 1;
  170.             tflag = 1;
  171.             break;
  172.  
  173.         case '?':
  174.         default:
  175.             usage();
  176.         }
  177.     argc -= optind;
  178.     argv += optind;
  179.  
  180. #ifdef KERBEROS
  181. #ifdef CRYPT
  182.     shell = doencrypt ? "ekshell" : "kshell";
  183. #else
  184.     shell = "kshell";
  185. #endif
  186.     sp = getservbyname(shell, "tcp");
  187.     if (sp == NULL) {
  188.         char    msgbuf[64];
  189.         use_kerberos = 0;
  190.         (void)snprintf(msgbuf, sizeof(msgbuf),
  191.             "can't get entry for %s/tcp service", shell);
  192.         old_warning(msgbuf);
  193.         sp = getservbyname(shell = "shell", "tcp");
  194.     }
  195. #else
  196.     sp = getservbyname(shell = "shell", "tcp");
  197. #endif
  198.     if (sp == NULL) {
  199.         (void)fprintf(stderr, "rcp: %s/tcp: unknown service\n", shell);
  200.         exit(1);
  201.     }
  202.     port = sp->s_port;
  203.  
  204.     if (!(pwd = getpwuid(userid = getuid()))) {
  205.         (void)fprintf(stderr, "rcp: unknown user %d.\n", (int)userid);
  206.         exit(1);
  207.     }
  208.  
  209.     if (fflag) {
  210.         /* follow "protocol", send data */
  211.         (void)response();
  212.         (void)setuid(userid);
  213.         source(argc, argv);
  214.         exit(errs);
  215.     }
  216.  
  217.     if (tflag) {
  218.         /* receive data */
  219.         (void)setuid(userid);
  220.         sink(argc, argv);
  221.         exit(errs);
  222.     }
  223.  
  224.     if (argc < 2)
  225.         usage();
  226.     if (argc > 2)
  227.         targetshouldbedirectory = 1;
  228.  
  229.     rem = -1;
  230.     /* command to be executed on remote system using "rsh" */
  231. #ifdef    KERBEROS
  232.     (void)snprintf(cmd, sizeof(cmd),
  233.         "rcp%s%s%s%s", iamrecursive ? " -r" : "",
  234. #ifdef CRYPT
  235.         ((doencrypt && use_kerberos) ? " -x" : ""),
  236. #else
  237.         "",
  238. #endif
  239.         pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
  240. #else
  241.     (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s",
  242.         iamrecursive ? " -r" : "", pflag ? " -p" : "",
  243.         targetshouldbedirectory ? " -d" : "");
  244. #endif
  245.  
  246.     (void)signal(SIGPIPE, lostconn);
  247.  
  248.     if (targ = colon(argv[argc - 1]))
  249.         toremote(targ, argc, argv);    /* destination is remote host */
  250.     else {
  251.         tolocal(argc, argv);        /* destination is local host */
  252.         if (targetshouldbedirectory)
  253.             verifydir(argv[argc - 1]);
  254.     }
  255.     exit(errs);
  256. }
  257.  
  258. toremote(targ, argc, argv)
  259.     char *targ;
  260.     int argc;
  261.     char **argv;
  262. {
  263.     int i, len, tos;
  264.     char *bp, *host, *src, *suser, *thost, *tuser;
  265.     char *colon();
  266.  
  267.     *targ++ = 0;
  268.     if (*targ == 0)
  269.         targ = ".";
  270.  
  271.     if (thost = index(argv[argc - 1], '@@')) {
  272.         /* user@@host */
  273.         *thost++ = 0;
  274.         tuser = argv[argc - 1];
  275.         if (*tuser == '\0')
  276.             tuser = NULL;
  277.         else if (!okname(tuser))
  278.             exit(1);
  279.     } else {
  280.         thost = argv[argc - 1];
  281.         tuser = NULL;
  282.     }
  283.  
  284.     for (i = 0; i < argc - 1; i++) {
  285.         src = colon(argv[i]);
  286.         if (src) {            /* remote to remote */
  287.             *src++ = 0;
  288.             if (*src == 0)
  289.                 src = ".";
  290.             host = index(argv[i], '@@');
  291.             len = strlen(_PATH_RSH) + strlen(argv[i]) +
  292.                 strlen(src) + (tuser ? strlen(tuser) : 0) +
  293.                 strlen(thost) + strlen(targ) + CMDNEEDS + 20;
  294.             if (!(bp = malloc(len)))
  295.                 nospace();
  296.             if (host) {
  297.                 *host++ = 0;
  298.                 suser = argv[i];
  299.                 if (*suser == '\0')
  300.                     suser = pwd->pw_name;
  301.                 else if (!okname(suser))
  302.                     continue;
  303.                 (void)snprintf(bp, len,
  304.                     "%s %s -l %s -n %s %s '%s%s%s:%s'",
  305.                     _PATH_RSH, host, suser, cmd, src,
  306.                     tuser ? tuser : "", tuser ? "@@" : "",
  307.                     thost, targ);
  308.             } else
  309.                 (void)snprintf(bp, len,
  310.                     "%s %s -n %s %s '%s%s%s:%s'",
  311.                     _PATH_RSH, argv[i], cmd, src,
  312.                     tuser ? tuser : "", tuser ? "@@" : "",
  313.                     thost, targ);
  314.             (void)susystem(bp);
  315.             (void)free(bp);
  316.         } else {            /* local to remote */
  317.             if (rem == -1) {
  318.                 len = strlen(targ) + CMDNEEDS + 20;
  319.                 if (!(bp = malloc(len)))
  320.                     nospace();
  321.                 (void)snprintf(bp, len, "%s -t %s", cmd, targ);
  322.                 host = thost;
  323. #ifdef KERBEROS
  324.                 if (use_kerberos)
  325.                     rem = kerberos(&host, bp,
  326.                         pwd->pw_name,
  327.                         tuser ? tuser : pwd->pw_name);
  328.                 else
  329. #endif
  330.                     rem = rcmd(&host, port, pwd->pw_name,
  331.                         tuser ? tuser : pwd->pw_name,
  332.                         bp, 0);
  333.                 if (rem < 0)
  334.                     exit(1);
  335.                 tos = IPTOS_THROUGHPUT;
  336.                 if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  337.                     (char *)&tos, sizeof(int)) < 0)
  338.                     perror("rcp: setsockopt TOS (ignored)");
  339.                 if (response() < 0)
  340.                     exit(1);
  341.                 (void)free(bp);
  342.                 (void)setuid(userid);
  343.             }
  344.             source(1, argv+i);
  345.         }
  346.     }
  347. }
  348.  
  349. tolocal(argc, argv)
  350.     int argc;
  351.     char **argv;
  352. {
  353.     int i, len, tos;
  354.     char *bp, *host, *src, *suser;
  355.     char *colon();
  356.  
  357.     for (i = 0; i < argc - 1; i++) {
  358.         if (!(src = colon(argv[i]))) {    /* local to local */
  359.             len = strlen(_PATH_CP) + strlen(argv[i]) +
  360.                 strlen(argv[argc - 1]) + 20;
  361.             if (!(bp = malloc(len)))
  362.                 nospace();
  363.             (void)snprintf(bp, len, "%s%s%s %s %s", _PATH_CP,
  364.                 iamrecursive ? " -r" : "", pflag ? " -p" : "",
  365.                 argv[i], argv[argc - 1]);
  366.             (void)susystem(bp);
  367.             (void)free(bp);
  368.             continue;
  369.         }
  370.         *src++ = 0;
  371.         if (*src == 0)
  372.             src = ".";
  373.         host = index(argv[i], '@@');
  374.         if (host) {
  375.             *host++ = 0;
  376.             suser = argv[i];
  377.             if (*suser == '\0')
  378.                 suser = pwd->pw_name;
  379.             else if (!okname(suser))
  380.                 continue;
  381.         } else {
  382.             host = argv[i];
  383.             suser = pwd->pw_name;
  384.         }
  385.         len = strlen(src) + CMDNEEDS + 20;
  386.         if (!(bp = malloc(len)))
  387.             nospace();
  388.         (void)snprintf(bp, len, "%s -f %s", cmd, src);
  389. #ifdef KERBEROS
  390.         if (use_kerberos)
  391.             rem = kerberos(&host, bp, pwd->pw_name, suser);
  392.         else
  393. #endif
  394.             rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0);
  395.         (void)free(bp);
  396.         if (rem < 0)
  397.             continue;
  398.         (void)seteuid(userid);
  399.         tos = IPTOS_THROUGHPUT;
  400.         if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  401.             (char *)&tos, sizeof(int)) < 0)
  402.             perror("rcp: setsockopt TOS (ignored)");
  403.         sink(1, argv + argc - 1);
  404.         (void)seteuid(0);
  405.         (void)close(rem);
  406.         rem = -1;
  407.     }
  408. }
  409.  
  410. verifydir(cp)
  411.     char *cp;
  412. {
  413.     struct stat stb;
  414.  
  415.     if (stat(cp, &stb) >= 0) {
  416.         if ((stb.st_mode & S_IFMT) == S_IFDIR)
  417.             return;
  418.         errno = ENOTDIR;
  419.     }
  420.     error("rcp: %s: %s.\n", cp, strerror(errno));
  421.     exit(1);
  422. }
  423.  
  424. char *
  425. colon(cp)
  426.     register char *cp;
  427. {
  428.     for (; *cp; ++cp) {
  429.         if (*cp == ':')
  430.             return(cp);
  431.         if (*cp == '/')
  432.             return(0);
  433.     }
  434.     return(0);
  435. }
  436.  
  437. okname(cp0)
  438.     char *cp0;
  439. {
  440.     register char *cp = cp0;
  441.     register int c;
  442.  
  443.     do {
  444.         c = *cp;
  445.         if (c & 0200)
  446.             goto bad;
  447.         if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
  448.             goto bad;
  449.     } while (*++cp);
  450.     return(1);
  451. bad:
  452.     (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0);
  453.     return(0);
  454. }
  455.  
  456. susystem(s)
  457.     char *s;
  458. {
  459.     int status, pid, w;
  460.     register sig_t istat, qstat;
  461.  
  462.     if ((pid = vfork()) == 0) {
  463.         (void)setuid(userid);
  464.         execl(_PATH_BSHELL, "sh", "-c", s, (char *)0);
  465.         _exit(127);
  466.     }
  467.     istat = signal(SIGINT, SIG_IGN);
  468.     qstat = signal(SIGQUIT, SIG_IGN);
  469.     while ((w = wait(&status)) != pid && w != -1)
  470.         ;
  471.     if (w == -1)
  472.         status = -1;
  473.     (void)signal(SIGINT, istat);
  474.     (void)signal(SIGQUIT, qstat);
  475.     return(status);
  476. }
  477.  
  478. source(argc, argv)
  479.     int argc;
  480.     char **argv;
  481. {
  482.     struct stat stb;
  483.     static BUF buffer;
  484.     BUF *bp;
  485.     off_t i;
  486.     int x, readerr, f, amt;
  487.     char *last, *name, buf[BUFSIZ];
  488.     BUF *allocbuf();
  489.  
  490.     for (x = 0; x < argc; x++) {
  491.         name = argv[x];
  492.         if ((f = open(name, O_RDONLY, 0)) < 0) {
  493.             error("rcp: %s: %s\n", name, strerror(errno));
  494.             continue;
  495.         }
  496.         if (fstat(f, &stb) < 0)
  497.             goto notreg;
  498.         switch (stb.st_mode&S_IFMT) {
  499.  
  500.         case S_IFREG:
  501.             break;
  502.  
  503.         case S_IFDIR:
  504.             if (iamrecursive) {
  505.                 (void)close(f);
  506.                 rsource(name, &stb);
  507.                 continue;
  508.             }
  509.             /* FALLTHROUGH */
  510.         default:
  511. notreg:            (void)close(f);
  512.             error("rcp: %s: not a plain file\n", name);
  513.             continue;
  514.         }
  515.         last = rindex(name, '/');
  516.         if (last == 0)
  517.             last = name;
  518.         else
  519.             last++;
  520.         if (pflag) {
  521.             /*
  522.              * Make it compatible with possible future
  523.              * versions expecting microseconds.
  524.              */
  525.             (void)snprintf(buf, sizeof(buf),
  526.                 "T%ld 0 %ld 0\n", stb.st_mtime, stb.st_atime);
  527.             (void)write(rem, buf, (int)strlen(buf));
  528.             if (response() < 0) {
  529.                 (void)close(f);
  530.                 continue;
  531.             }
  532.         }
  533.         (void)snprintf(buf, sizeof(buf),
  534.             "C%04o %ld %s\n", stb.st_mode&07777, stb.st_size, last);
  535.         (void)write(rem, buf, (int)strlen(buf));
  536.         if (response() < 0) {
  537.             (void)close(f);
  538.             continue;
  539.         }
  540.         if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
  541.             (void)close(f);
  542.             continue;
  543.         }
  544.         readerr = 0;
  545.         for (i = 0; i < stb.st_size; i += bp->cnt) {
  546.             amt = bp->cnt;
  547.             if (i + amt > stb.st_size)
  548.                 amt = stb.st_size - i;
  549.             if (readerr == 0 && read(f, bp->buf, amt) != amt)
  550.                 readerr = errno;
  551.             (void)write(rem, bp->buf, amt);
  552.         }
  553.         (void)close(f);
  554.         if (readerr == 0)
  555.             (void)write(rem, "", 1);
  556.         else
  557.             error("rcp: %s: %s\n", name, strerror(readerr));
  558.         (void)response();
  559.     }
  560. }
  561.  
  562. rsource(name, statp)
  563.     char *name;
  564.     struct stat *statp;
  565. {
  566.     DIR *dirp;
  567.     struct dirent *dp;
  568.     char *last, *vect[1], path[MAXPATHLEN];
  569.  
  570.     if (!(dirp = opendir(name))) {
  571.         error("rcp: %s: %s\n", name, strerror(errno));
  572.         return;
  573.     }
  574.     last = rindex(name, '/');
  575.     if (last == 0)
  576.         last = name;
  577.     else
  578.         last++;
  579.     if (pflag) {
  580.         (void)snprintf(path, sizeof(path),
  581.             "T%ld 0 %ld 0\n", statp->st_mtime, statp->st_atime);
  582.         (void)write(rem, path, (int)strlen(path));
  583.         if (response() < 0) {
  584.             closedir(dirp);
  585.             return;
  586.         }
  587.     }
  588.     (void)snprintf(path, sizeof(path),
  589.         "D%04o %d %s\n", statp->st_mode&07777, 0, last);
  590.     (void)write(rem, path, (int)strlen(path));
  591.     if (response() < 0) {
  592.         closedir(dirp);
  593.         return;
  594.     }
  595.     while (dp = readdir(dirp)) {
  596.         if (dp->d_ino == 0)
  597.             continue;
  598.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  599.             continue;
  600.         if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
  601.             error("%s/%s: name too long.\n", name, dp->d_name);
  602.             continue;
  603.         }
  604.         (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
  605.         vect[0] = path;
  606.         source(1, vect);
  607.     }
  608.     closedir(dirp);
  609.     (void)write(rem, "E\n", 2);
  610.     (void)response();
  611. }
  612.  
  613. response()
  614. {
  615.     register char *cp;
  616.     char ch, resp, rbuf[BUFSIZ];
  617.  
  618.     if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
  619.         lostconn();
  620.  
  621.     cp = rbuf;
  622.     switch(resp) {
  623.     case 0:                /* ok */
  624.         return(0);
  625.     default:
  626.         *cp++ = resp;
  627.         /* FALLTHROUGH */
  628.     case 1:                /* error, followed by err msg */
  629.     case 2:                /* fatal error, "" */
  630.         do {
  631.             if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  632.                 lostconn();
  633.             *cp++ = ch;
  634.         } while (cp < &rbuf[BUFSIZ] && ch != '\n');
  635.  
  636.         if (!iamremote)
  637.             (void)write(2, rbuf, cp - rbuf);
  638.         ++errs;
  639.         if (resp == 1)
  640.             return(-1);
  641.         exit(1);
  642.     }
  643.     /*NOTREACHED*/
  644. }
  645.  
  646. void
  647. lostconn()
  648. {
  649.     if (!iamremote)
  650.         (void)fprintf(stderr, "rcp: lost connection\n");
  651.     exit(1);
  652. }
  653.  
  654. sink(argc, argv)
  655.     int argc;
  656.     char **argv;
  657. {
  658.     register char *cp;
  659.     static BUF buffer;
  660.     struct stat stb;
  661.     struct timeval tv[2];
  662.     enum { YES, NO, DISPLAYED } wrerr;
  663.     BUF *bp, *allocbuf();
  664.     off_t i, j;
  665.     char ch, *targ, *why;
  666.     int amt, count, exists, first, mask, mode;
  667.     int ofd, setimes, size, targisdir;
  668.     char *np, *vect[1], buf[BUFSIZ];
  669.  
  670. #define    atime    tv[0]
  671. #define    mtime    tv[1]
  672. #define    SCREWUP(str)    { why = str; goto screwup; }
  673.  
  674.     setimes = targisdir = 0;
  675.     mask = umask(0);
  676.     if (!pflag)
  677.         (void)umask(mask);
  678.     if (argc != 1) {
  679.         error("rcp: ambiguous target\n");
  680.         exit(1);
  681.     }
  682.     targ = *argv;
  683.     if (targetshouldbedirectory)
  684.         verifydir(targ);
  685.     (void)write(rem, "", 1);
  686.     if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
  687.         targisdir = 1;
  688.     for (first = 1;; first = 0) {
  689.         cp = buf;
  690.         if (read(rem, cp, 1) <= 0)
  691.             return;
  692.         if (*cp++ == '\n')
  693.             SCREWUP("unexpected <newline>");
  694.         do {
  695.             if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  696.                 SCREWUP("lost connection");
  697.             *cp++ = ch;
  698.         } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
  699.         *cp = 0;
  700.  
  701.         if (buf[0] == '\01' || buf[0] == '\02') {
  702.             if (iamremote == 0)
  703.                 (void)write(2, buf + 1, (int)strlen(buf + 1));
  704.             if (buf[0] == '\02')
  705.                 exit(1);
  706.             errs++;
  707.             continue;
  708.         }
  709.         if (buf[0] == 'E') {
  710.             (void)write(rem, "", 1);
  711.             return;
  712.         }
  713.  
  714.         if (ch == '\n')
  715.             *--cp = 0;
  716.  
  717. #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
  718.         cp = buf;
  719.         if (*cp == 'T') {
  720.             setimes++;
  721.             cp++;
  722.             getnum(mtime.tv_sec);
  723.             if (*cp++ != ' ')
  724.                 SCREWUP("mtime.sec not delimited");
  725.             getnum(mtime.tv_usec);
  726.             if (*cp++ != ' ')
  727.                 SCREWUP("mtime.usec not delimited");
  728.             getnum(atime.tv_sec);
  729.             if (*cp++ != ' ')
  730.                 SCREWUP("atime.sec not delimited");
  731.             getnum(atime.tv_usec);
  732.             if (*cp++ != '\0')
  733.                 SCREWUP("atime.usec not delimited");
  734.             (void)write(rem, "", 1);
  735.             continue;
  736.         }
  737.         if (*cp != 'C' && *cp != 'D') {
  738.             /*
  739.              * Check for the case "rcp remote:foo\* local:bar".
  740.              * In this case, the line "No match." can be returned
  741.              * by the shell before the rcp command on the remote is
  742.              * executed so the ^Aerror_message convention isn't
  743.              * followed.
  744.              */
  745.             if (first) {
  746.                 error("%s\n", cp);
  747.                 exit(1);
  748.             }
  749.             SCREWUP("expected control record");
  750.         }
  751.         mode = 0;
  752.         for (++cp; cp < buf + 5; cp++) {
  753.             if (*cp < '0' || *cp > '7')
  754.                 SCREWUP("bad mode");
  755.             mode = (mode << 3) | (*cp - '0');
  756.         }
  757.         if (*cp++ != ' ')
  758.             SCREWUP("mode not delimited");
  759.         size = 0;
  760.         while (isdigit(*cp))
  761.             size = size * 10 + (*cp++ - '0');
  762.         if (*cp++ != ' ')
  763.             SCREWUP("size not delimited");
  764.         if (targisdir) {
  765.             static char *namebuf;
  766.             static int cursize;
  767.             size_t need;
  768.  
  769.             need = strlen(targ) + strlen(cp) + 250;
  770.             if (need > cursize) {
  771.                 if (!(namebuf = malloc(need)))
  772.                     error("out of memory\n");
  773.             }
  774.             (void)snprintf(namebuf, need, "%s%s%s", targ,
  775.                 *targ ? "/" : "", cp);
  776.             np = namebuf;
  777.         }
  778.         else
  779.             np = targ;
  780.         exists = stat(np, &stb) == 0;
  781.         if (buf[0] == 'D') {
  782.             if (exists) {
  783.                 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
  784.                     errno = ENOTDIR;
  785.                     goto bad;
  786.                 }
  787.                 if (pflag)
  788.                     (void)chmod(np, mode);
  789.             } else if (mkdir(np, mode) < 0)
  790.                 goto bad;
  791.             vect[0] = np;
  792.             sink(1, vect);
  793.             if (setimes) {
  794.                 setimes = 0;
  795.                 if (utimes(np, tv) < 0)
  796.                     error("rcp: can't set times on %s: %s\n",
  797.                     np, strerror(errno));
  798.             }
  799.             continue;
  800.         }
  801.         if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
  802. bad:            error("rcp: %s: %s\n", np, strerror(errno));
  803.             continue;
  804.         }
  805.         if (exists && pflag)
  806.             (void)fchmod(ofd, mode);
  807.         (void)write(rem, "", 1);
  808.         if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) {
  809.             (void)close(ofd);
  810.             continue;
  811.         }
  812.         cp = bp->buf;
  813.         count = 0;
  814.         wrerr = NO;
  815.         for (i = 0; i < size; i += BUFSIZ) {
  816.             amt = BUFSIZ;
  817.             if (i + amt > size)
  818.                 amt = size - i;
  819.             count += amt;
  820.             do {
  821.                 j = read(rem, cp, amt);
  822.                 if (j <= 0) {
  823.                     error("rcp: %s\n",
  824.                         j ? strerror(errno) :
  825.                         "dropped connection");
  826.                     exit(1);
  827.                 }
  828.                 amt -= j;
  829.                 cp += j;
  830.             } while (amt > 0);
  831.             if (count == bp->cnt) {
  832.                 if (wrerr == NO &&
  833.                     write(ofd, bp->buf, count) != count)
  834.                     wrerr = YES;
  835.                 count = 0;
  836.                 cp = bp->buf;
  837.             }
  838.         }
  839.         if (count != 0 && wrerr == NO &&
  840.             write(ofd, bp->buf, count) != count)
  841.             wrerr = YES;
  842.         if (ftruncate(ofd, size)) {
  843.             error("rcp: can't truncate %s: %s\n", np,
  844.                 strerror(errno));
  845.             wrerr = DISPLAYED;
  846.         }
  847.         (void)close(ofd);
  848.         (void)response();
  849.         if (setimes && wrerr == NO) {
  850.             setimes = 0;
  851.             if (utimes(np, tv) < 0) {
  852.                 error("rcp: can't set times on %s: %s\n",
  853.                     np, strerror(errno));
  854.                 wrerr = DISPLAYED;
  855.             }
  856.         }
  857.         switch(wrerr) {
  858.         case YES:
  859.             error("rcp: %s: %s\n", np, strerror(errno));
  860.             break;
  861.         case NO:
  862.             (void)write(rem, "", 1);
  863.             break;
  864.         case DISPLAYED:
  865.             break;
  866.         }
  867.     }
  868. screwup:
  869.     error("rcp: protocol screwup: %s\n", why);
  870.     exit(1);
  871. }
  872.  
  873. BUF *
  874. allocbuf(bp, fd, blksize)
  875.     BUF *bp;
  876.     int fd, blksize;
  877. {
  878.     struct stat stb;
  879.     size_t size;
  880.  
  881.     if (fstat(fd, &stb) < 0) {
  882.         error("rcp: fstat: %s\n", strerror(errno));
  883.         return(0);
  884.     }
  885.     size = roundup(stb.st_blksize, blksize);
  886.     if (size == 0)
  887.         size = blksize;
  888.     if (bp->cnt < size) {
  889.         if (bp->buf != 0)
  890.             free(bp->buf);
  891.         bp->buf = malloc(size);
  892.         if (!bp->buf) {
  893.             error("rcp: malloc: out of memory\n");
  894.             return(0);
  895.         }
  896.     }
  897.     bp->cnt = size;
  898.     return(bp);
  899. }
  900.  
  901. /* VARARGS1 */
  902. error(fmt, a1, a2, a3)
  903.     char *fmt;
  904.     int a1, a2, a3;
  905. {
  906.     static FILE *fp;
  907.  
  908.     ++errs;
  909.     if (!fp && !(fp = fdopen(rem, "w")))
  910.         return;
  911.     (void)fprintf(fp, "%c", 0x01);
  912.     (void)fprintf(fp, fmt, a1, a2, a3);
  913.     (void)fflush(fp);
  914.     if (!iamremote)
  915.         (void)fprintf(stderr, fmt, a1, a2, a3);
  916. }
  917.  
  918. nospace()
  919. {
  920.     (void)fprintf(stderr, "rcp: out of memory.\n");
  921.     exit(1);
  922. }
  923.  
  924.  
  925. usage()
  926. {
  927. #ifdef KERBEROS
  928. #ifdef CRYPT
  929.     (void)fprintf(stderr, "%s\n\t%s\n",
  930.         "usage: rcp [-k realm] [-px] f1 f2",
  931.         "or: rcp [-k realm] [-rpx] f1 ... fn directory");
  932. #else
  933.     (void)fprintf(stderr, "%s\n\t%s\n",
  934.         "usage: rcp [-k realm] [-p] f1 f2",
  935.         "or: rcp [-k realm] [-rp] f1 ... fn directory");
  936. #endif
  937. #else
  938.     (void)fprintf(stderr,
  939.         "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n");
  940. #endif
  941.     exit(1);
  942. }
  943.  
  944. #ifdef KERBEROS
  945. old_warning(str)
  946.     char *str;
  947. {
  948.     (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str);
  949. }
  950.  
  951. int
  952. kerberos(host, bp, locuser, user)
  953.  
  954.     char **host, *bp, *locuser, *user;
  955. {
  956.     struct servent *sp;
  957.  
  958. again:
  959.     if (use_kerberos) {
  960.         rem = KSUCCESS;
  961.         errno = 0;
  962.         if (dest_realm == NULL)
  963.             dest_realm = krb_realmofhost(*host);
  964.  
  965. #ifdef CRYPT
  966.         if (doencrypt)
  967.             rem = krcmd_mutual(
  968.                 host, port,
  969.                 user, bp, 0,
  970.                     dest_realm,
  971.                 &cred, schedule);
  972.         else
  973. #endif
  974.             rem = krcmd(
  975.                 host, port,
  976.                 user, bp, 0, dest_realm);
  977.  
  978.         if (rem < 0) {
  979.             use_kerberos = 0;
  980.             sp = getservbyname("shell", "tcp");
  981.             if (sp == NULL) {
  982.                 (void)fprintf(stderr,
  983.                         "rcp: unknown service shell/tcp\n");
  984.                 exit(1);
  985.             }
  986.             if (errno == ECONNREFUSED)
  987.                 old_warning(
  988.                     "remote host doesn't support Kerberos");
  989.  
  990.             if (errno == ENOENT)
  991.                 old_warning(
  992.                     "Can't provide Kerberos auth data");
  993.             port = sp->s_port;
  994.             goto again;
  995.         }
  996.     } else {
  997. #ifdef CRYPT
  998.         if (doencrypt) {
  999.             fprintf(stderr,
  1000.                 "The -x option requires Kerberos authentication\n");
  1001.             exit(1);
  1002.         }
  1003. #endif
  1004.         rem = rcmd(host, sp->s_port, locuser, user, bp, 0);
  1005.     }
  1006.     return(rem);
  1007. }
  1008. #endif /* KERBEROS */
  1009. @
  1010.